import { readFile } from "node:fs";
import { createServer } from "node:http";
import { extname, join } from "node:path";
import { WebSocketServer } from "ws";
import logger from "./utils/logger";
import { watch } from "chokidar";

const HMR_CLIENT_PATH = "/@/z-hmr/";

// http dev server
const server = createServer((req, res) => {
  logger.log("get request: " + req.url);

  const parsedUrl = new URL(req.url!, "http://localhost");
  console.log("parsedUrl: ", parsedUrl.pathname, parsedUrl.search);

  let filePath = join(__dirname, parsedUrl.pathname);
  if (parsedUrl.pathname === "/") {
    filePath = join(__dirname, "./index.html");
  }

  if (parsedUrl.pathname.startsWith(HMR_CLIENT_PATH)) {
    // TODO dynamic compile and compress dependencies
    filePath = join(
      __dirname,
      parsedUrl.pathname.replace(HMR_CLIENT_PATH, "./dist/browser/")
    );
  }

  let contentType = "text/html";
  const ext = extname(filePath);
  switch (ext) {
    case ".html":
      contentType = "text/html";
      break;
    case ".js":
      contentType = "text/javascript";
      break;
    case ".css":
      contentType = "text/css";
      break;
    default:
      break;
  }

  logger.log("file path: ", filePath);
  readFile(filePath, (err, data) => {
    if (err) {
      console.error(err);
      res.writeHead(404);
      res.end("File not found");
      return;
    }

    // if file is html, add hmr client script
    if (ext === ".html") {
      res.setHeader("Content-Type", "text/html");
      res.end(
        data
          .toString()
          .replace(
            "</body>",
            `<script type="module" src="${HMR_CLIENT_PATH}client.js"></script></body>`
          ),
        "utf-8"
      );
      return;
    }

    res.writeHead(200, {
      "Content-Type": contentType,
    });
    res.end(data, "utf-8");
  });
});

// wss server
const wss = new WebSocketServer({ server });

wss.on("connection", (ws) => {
  ws.on("message", (message) => {
    console.log("Received message:", JSON.parse(message.toString()));
    ws.send(JSON.stringify({ type: "confirm" }));
  });
  ws.on("close", () => {
    console.log("Client disconnected");
  });
});

const PORT = 4000;
server.listen(PORT, () => {
  console.log(`Server is running at http://localhost:${PORT}`);
});

// chokidar watcher

const watcher = watch(["./examples", "./index.html"], {
  ignored: /node_modules/,
  persistent: true,
});

watcher.on("change", (path, stats) => {
  console.log("File", path, "has been changed");
  // send message to client for updating
  wss.clients.forEach((client) => {
    if (client.readyState === WebSocket.OPEN) {
      client.send(
        JSON.stringify({
          type: "change",
          path,
          timestamp: Date.now(),
        })
      );
    }
  });
});
